<script setup lang="ts">
import ToolView from "@/modules/tools/layout/tool-view.vue";
import { CopyOutlined, LinkOutlined, SearchOutlined } from "@ant-design/icons-vue";
import { hc } from "@/framework/vue/util/render.ts";
import { nextTick, ref, shallowRef, watch } from "vue";
import type { NpmPackageInfo, NpmPackageObject } from "./types.ts";
import { showMessageAndPrint } from "@/framework/util/log.ts";
import Grid from "@/components/framework/grid.vue";
import ScrollView from "@/components/framework/scroll-view.vue";
import { copyText } from "@/util/clipboard.ts";
import type { ScrollViewRef } from "@/components/framework/scroll-view-types.ts";
import { openExternal } from "@/util/shell.ts";
import { searchNpmPackages } from "./npm-search.service.ts";
import { useLocalShallowRef } from "@/framework/vue/hooks/state.ts";
import Gavatar from "@/components/app/gavatar.vue";
import dayjs from "dayjs";
import { formatDateTime1 } from "@/framework/util/date.ts";

const keyword = ref("");
const pageSize = ref(12);
const currentPage = ref(1);
const total = ref(0);
const packageList = shallowRef<NpmPackageObject[]>([]);
const loading = ref(false);

watch(pageSize, () => {
  currentPage.value = 1;
});

watch(currentPage, () => loadData());

const scroller = shallowRef<ScrollViewRef>();
watch(packageList, () =>
  nextTick(() => {
    scroller.value?.scrollTo(0);
  }),
);

const loadData = async () => {
  let text = keyword.value.trim();
  if (!text) {
    total.value = 0;
    packageList.value = [];
    return;
  }
  loading.value = true;
  try {
    text = encodeURIComponent(text);
    const size = pageSize.value;
    const from = (currentPage.value - 1) * size;
    const resp = await searchNpmPackages(text, from, size);
    total.value = resp.data.total;
    packageList.value = resp.data.objects || [];
  } catch (e) {
    showMessageAndPrint(e);
  } finally {
    loading.value = false;
  }
};

const keywordHistory = useLocalShallowRef<string[]>("tools.npm-search.keywordHistory", []);

const saveKeywordHistory = (kw: string) => {
  if (!keywordHistory.value.includes(kw)) {
    const list = [kw, ...keywordHistory.value];
    keywordHistory.value = list.slice(0, 10);
  }
};

const handleSearch = () => {
  currentPage.value = 1;
  loadData();

  const kw = keyword.value.trim();
  if (kw) {
    saveKeywordHistory(kw);
  }
};

const openDetail = (pkg: NpmPackageInfo) => {
  openExternal(`https://npmmirror.com/package/${pkg.name}`);
};
const openDetail1 = (pkg: NpmPackageInfo) => {
  openExternal(`https://www.npmjs.com/package/${pkg.name}`);
};
</script>

<template>
  <tool-view title="npm包查询" description="npm包查询">
    <grid row-template="auto 1fr auto">
      <div class="ph-10 pv-20 flex col-gap-10">
        <a-dropdown trigger="focus" placement="bottom">
          <a-input v-model:value="keyword" placeholder="搜索NPM包 . . ." allow-clear @keyup.enter="handleSearch" class="flex-1" />
          <template #overlay>
            <div class="bg-container border border-radius box-shadow2 p-10">
              <a-tag v-for="it in keywordHistory" color="var(--color-primary)" @click="keyword = it">{{ it }}</a-tag>
            </div>
          </template>
        </a-dropdown>
        <a-button type="primary" shape="circle" :icon="hc(SearchOutlined)" @click="handleSearch" />
      </div>
      <div class="overflow-auto position-relative">
        <scroll-view ref="scroller">
          <template v-for="it in packageList" :key="it.package.name">
            <div class="package-item">
              <div class="flex-column row-gap-10 flex-wrap flex-1">
                <div class="flex aic col-gap-10">
                  <b class="package-name font-16 select-text">{{ it.package.name }}@{{ it.package.version }}</b>
                </div>
                <div class="color-text-secondary select-text">{{ it.package.description }}</div>
                <template v-if="it.package['dist-tags']">
                  <div>
                    <a-tag v-for="kw in it.package.keywords" :key="kw" color="pink">{{ kw }}</a-tag>
                  </div>
                </template>
              </div>
              <div class="flex-column ai-end jc-sb">
                <a-space>
                  <a-dropdown>
                    <a-button type="text" shape="circle" :icon="hc(LinkOutlined)" @click="openDetail(it.package)" />
                    <template #overlay>
                      <a-menu>
                        <a-menu-item :icon="hc(LinkOutlined)" @click="openDetail1(it.package)">在npmjs.com打开</a-menu-item>
                      </a-menu>
                    </template>
                  </a-dropdown>
                  <a-button type="text" shape="circle" :icon="hc(CopyOutlined)" @click="copyText(it.package.name)" />
                </a-space>
                <div class="flex aic col-gap-10">
                  <template v-if="it.package._npmUser">
                    <span>由</span>
                    <a-tooltip :title="it.package._npmUser.name" :mouse-leave-delay="0">
                      <gavatar :email="it.package._npmUser.email" />
                    </a-tooltip>
                  </template>
                  <a-tooltip
                    v-if="it.package.publish_time || it.package.modified"
                    :title="formatDateTime1(it.package.publish_time || it.package.modified)"
                    :mouse-leave-delay="0"
                  >
                    <span class="color-text-secondary">发布于 {{ dayjs(it.package.publish_time || it.package.modified).fromNow() }}</span>
                  </a-tooltip>
                </div>
              </div>
            </div>
          </template>
        </scroll-view>

        <div class="abs-fill flex-center" v-if="loading">
          <a-spin spinning size="large" />
        </div>
      </div>
      <div class="p-10">
        <a-pagination :total="total" v-model:current="currentPage" v-model:page-size="pageSize" />
      </div>
    </grid>
  </tool-view>
</template>

<style scoped lang="less">
.package-item {
  display: flex;
  column-gap: 10px;
  background: var(--color-bg-container);
  padding: 10px;
  border-radius: var(--border-radius);
  transition: all 0.2s;
  border: 1px solid transparent;
  margin: 0 10px 10px;
  box-shadow: var(--box-shadow1);

  .package-name {
    transition: all 0.2s;
  }

  &:hover {
    //background: var(--color-bg-text-hover);
    border-color: var(--color-primary);

    .package-name {
      color: var(--color-primary);
    }
  }
}
</style>
